Skip to content

feat: Add theme switching and group client settings#72

Open
alishair7071 wants to merge 1 commit intoAOSSIE-Org:mainfrom
alishair7071:feat/theme-switching-client-settings
Open

feat: Add theme switching and group client settings#72
alishair7071 wants to merge 1 commit intoAOSSIE-Org:mainfrom
alishair7071:feat/theme-switching-client-settings

Conversation

@alishair7071
Copy link
Contributor

@alishair7071 alishair7071 commented Feb 12, 2026

Summary

Added theme switching functionality and grouped all client-side settings in a dedicated section below the Save Config button.

Fixes #70

Changes

  • Added theme selector dropdown (Dark/Light themes)
  • Grouped Mouse Sensitivity, Invert Scroll, and Theme under "Client Settings" heading
  • Theme persists to localStorage and applies immediately on change
  • ThemeInit component loads saved theme on app startup

Testing

  • Change theme in settings - UI updates instantly
  • Refresh page - theme persists
  • Client settings are clearly separated from server settings
Rein.Theme.Switching.mp4

Summary by CodeRabbit

  • New Features

    • Added theme selector to settings with light and dark options
    • User theme preference now persists across sessions
  • Style

    • Updated default interface styling

 Add theme selector Dark/Light in settings page
 Group Mouse Sensitivity, Invert Scroll, and Theme under 'Client Settings' section
 Persist theme to localStorage (rein-theme)
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 12, 2026

📝 Walkthrough

Walkthrough

The pull request introduces theme switching functionality to the application. A ThemeInit component initializes the theme from localStorage on app startup, while the settings page gains a new "Client Settings" section with a theme selector dropdown, alongside mouse sensitivity and scroll inversion toggles, with all client settings persisted to localStorage.

Changes

Cohort / File(s) Summary
Theme Initialization
src/routes/__root.tsx
Added ThemeInit component that reads theme from localStorage on mount, validates against available themes, and applies data-theme attribute to document element. Updated body CSS classes from dark baseline to light/dynamic baseline.
Settings UI & Theme State
src/routes/settings.tsx
Added client-side state for theme with localStorage persistence. Implemented effect hook to sync theme changes to localStorage and DOM. Reorganized UI to group Mouse Sensitivity, Invert Scroll, and Theme selector in a dedicated "Client Settings" section.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant SettingsPage as Settings Page
    participant State as React State
    participant Storage as localStorage
    participant DOM

    User->>SettingsPage: Select theme from dropdown
    SettingsPage->>State: Update theme state
    State->>Storage: Persist theme to localStorage
    State->>DOM: Apply data-theme attribute
    DOM->>DOM: Re-render with new theme styles

    Note over SettingsPage,DOM: On app startup (via __root.tsx)
    SettingsPage->>Storage: Read theme from localStorage
    Storage-->>State: Initialize theme state
    State->>DOM: Apply saved data-theme attribute
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • client-server-settings #66: Modifies src/routes/settings.tsx to add client-side state and localStorage persistence for client settings, sharing the same pattern and functionality scope as this PR.

Poem

🐰 A theme switcher hops into view,
Dark or light, the choice is for you!
Settings grouped, all neat and tidy,
localStorage keeps them nightly,
The rabbit's warren is bright with delight! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding theme switching functionality and grouping client settings together in the UI.
Linked Issues check ✅ Passed The PR implements both requirements from issue #70: theme switching with persistence via localStorage and a grouped 'Client Settings' section containing Mouse Sensitivity, Invert Scroll, and Theme selector.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing theme switching and grouping client settings as specified in issue #70; no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/routes/settings.tsx`:
- Around line 234-238: The helper label currently rendering the invertScroll
helper text should be changed to a non-form label element (e.g., a <span> or
<p>) so it isn't treated as a form label, and the Theme label must be associated
with its control by adding htmlFor on the label and a matching id on the
<select> element (update the Theme label and the corresponding <select> in the
settings component, referencing the invertScroll helper text and the theme
<select> control by their existing JSX locations/names) — replace the decorative
<label> for invertScroll with a <span> or <p>, and add id="theme" (or another
unique id) to the <select> and htmlFor="theme" to the Theme <label>.
🧹 Nitpick comments (2)
src/routes/__root.tsx (1)

28-36: Theme may flash (FOUC) on page load.

useEffect runs after the first paint, so users may briefly see the default/unstyled theme before data-theme is applied. For a seamless experience, consider moving the theme initialization to a synchronous inline <script> in the <head> (before any body content renders) that reads localStorage and sets data-theme on <html>.

That said, this is a minor UX polish item and fine to defer.

src/routes/settings.tsx (1)

15-30: Consider centralizing localStorage keys in APP_CONFIG.

'rein_invert' (line 18) and 'rein_sensitivity' (line 27) are hardcoded strings, while the theme key uses APP_CONFIG.THEME_STORAGE_KEY. For consistency and easier refactoring, consider moving all localStorage keys into APP_CONFIG.

Comment on lines +234 to +238
<label className="label">
<span className="label-text-alt opacity-50">
{invertScroll ? 'Traditional scrolling enabled' : 'Natural scrolling'}
</span>
</label>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Accessibility: labels not associated with their controls.

The static analysis tool correctly flags these two <label> elements. The helper-text label at line 234 and the "Theme" label at line 242 lack htmlFor attributes and don't wrap their associated controls.

For the Theme label, add htmlFor pointing to the <select>, and give the select an id. The helper-text label for Invert Scroll is purely decorative — consider using a <span> or <p> instead of <label>.

Proposed fix
-                    <label className="label">
+                    <span className="label">
                         <span className="label-text-alt opacity-50">
                             {invertScroll ? 'Traditional scrolling enabled' : 'Natural scrolling'}
                         </span>
-                    </label>
+                    </span>
-                    <label className="label">
+                    <label className="label" htmlFor="theme-select">
                         <span className="label-text">Theme</span>
                     </label>
                     <select
                         className="select select-bordered w-full"
+                        id="theme-select"
                         value={theme}
                         onChange={(e) => setTheme(e.target.value)}
                     >

Also applies to: 242-244

🧰 Tools
🪛 Biome (2.3.14)

[error] 234-238: A form label must be associated with an input.

Consider adding a for or htmlFor attribute to the label element or moving the input element to inside the label element.

(lint/a11y/noLabelWithoutControl)

🤖 Prompt for AI Agents
In `@src/routes/settings.tsx` around lines 234 - 238, The helper label currently
rendering the invertScroll helper text should be changed to a non-form label
element (e.g., a <span> or <p>) so it isn't treated as a form label, and the
Theme label must be associated with its control by adding htmlFor on the label
and a matching id on the <select> element (update the Theme label and the
corresponding <select> in the settings component, referencing the invertScroll
helper text and the theme <select> control by their existing JSX
locations/names) — replace the decorative <label> for invertScroll with a <span>
or <p>, and add id="theme" (or another unique id) to the <select> and
htmlFor="theme" to the Theme <label>.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Settings UI: add theme switching and group client settings (sensitivity, invert, theme) in one section

1 participant